package contest.controller;

import contest.util.AuthorizePage;
import contest.util.IDataSource;
import contest.util.ISessionProperties;
import contest.util.LanguageBundle;
import contest.util.PropertiesBundle;
import contest.util.ResPathConstant;
import contest.util.SqlBundle;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.servlet.http.Cookie;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.xml.sax.SAXException;

public abstract class WebInit extends HttpServlet {

    protected static IDataSource DB_SETTING;
    private static ArrayList<ISessionProperties> SESSION_SETTING_LIST;
    protected static LanguageBundle LANGUAGE;
    protected static AuthorizePage AUTHORIZE_PAGE;
    protected static SqlBundle SQL_BUNDLE;
    protected SessionProcess sessionProcess;

    //LOAD CONFIG FOR REQUEST
    protected void loadRequest(HttpServletRequest request) throws MalformedURLException, ParserConfigurationException, SAXException, IOException {

        if (DB_SETTING == null) {
            DB_SETTING = this.parseContextXML();
        }

        if (SESSION_SETTING_LIST == null) {
            SESSION_SETTING_LIST = this.parseSessionXML();
        }

        if (!SqlBundle.getInstance().isBuilt()) {
            String absolutePath = getServletContext().getRealPath(ResPathConstant.SQL_FOLDER);
            SqlBundle.getInstance().buildPath(absolutePath);
            SQL_BUNDLE = SqlBundle.getInstance();
        }

        if (!LanguageBundle.getInstance().isBuilt()) {
            String absolutePath = getServletContext().getRealPath(ResPathConstant.LANGUAGE_FOLDER);
            LanguageBundle.getInstance().buildPath(absolutePath);
            LANGUAGE = LanguageBundle.getInstance();
        }

        if (AUTHORIZE_PAGE == null) {
            AUTHORIZE_PAGE = this.parseAuthorizeXML();
        }

        this.sessionProcess = new SessionProcess(request.getSession(), SESSION_SETTING_LIST);

    }

    // <editor-fold defaultstate="collapsed" desc="PARSE FILE. Click on the + sign on the left to edit the code.">
    //parse file context.xml
    private IDataSource parseContextXML() throws ParserConfigurationException, SAXException, IOException {

        DatabaseSource dataSourceTO = new DatabaseSource();
        String pathSource = getServletContext().getRealPath(ResPathConstant.CONTEXT_XML);
        DocumentBuilderFactory fap = DocumentBuilderFactory.newInstance();
        DocumentBuilder build = fap.newDocumentBuilder();
        File fi = new File(pathSource);
        Document document = build.parse(fi);
        Element ele = document.getDocumentElement();
        NodeList list = ele.getElementsByTagName("datasource");
        if (list.getLength() == 1) {
            Node no = list.item(0);
            NamedNodeMap attributes = no.getAttributes();
            dataSourceTO.setUsername(attributes.getNamedItem("username").getNodeValue());
            dataSourceTO.setPassword(attributes.getNamedItem("password").getNodeValue());
            dataSourceTO.setDriver(attributes.getNamedItem("driver").getNodeValue());
            dataSourceTO.setUrl(attributes.getNamedItem("url").getNodeValue());
            return dataSourceTO;
        }
        return null;
    }

    //parse file session.xml
    private ArrayList<ISessionProperties> parseSessionXML() throws ParserConfigurationException, SAXException, IOException {

        ArrayList<ISessionProperties> sessionPropertiesList = new ArrayList<ISessionProperties>();
        ISessionProperties sessionPropertiesTO = null;
        String pathSource = getServletContext().getRealPath(ResPathConstant.SESSION_XML);
        DocumentBuilderFactory fap = DocumentBuilderFactory.newInstance();
        DocumentBuilder build = fap.newDocumentBuilder();
        File fi = new File(pathSource);
        Document document = build.parse(fi);
        Element ele = document.getDocumentElement();
        NodeList list = ele.getElementsByTagName("item");
        for (int i = 0; i < list.getLength(); i++) {
            Node no = list.item(i);
            NamedNodeMap attributes = no.getAttributes();
            sessionPropertiesTO = new SessionProperties(attributes.getNamedItem("name").getNodeValue(), attributes.getNamedItem("status").getNodeValue());
            ((SessionProperties) sessionPropertiesTO).setAllowRemove(attributes.getNamedItem("allowRemove").getNodeValue());
            sessionPropertiesList.add(sessionPropertiesTO);
        }
        return sessionPropertiesList;

    }

    //parse authorize.xml
    private AuthorizePage parseAuthorizeXML() throws ParserConfigurationException, SAXException, IOException {
        AuthorizePage authPage = new AuthorizePage();
        String pathSource = getServletContext().getRealPath(ResPathConstant.AUTHORIZE_XML);
        DocumentBuilderFactory fap = DocumentBuilderFactory.newInstance();
        DocumentBuilder build = fap.newDocumentBuilder();
        File fi = new File(pathSource);
        Document document = build.parse(fi);
        Element ele = document.getDocumentElement();
        NodeList list = ele.getElementsByTagName("user");
        for (int i = 0; list != null && i < list.getLength(); i++) {
            Node userNode = list.item(i);
            Node roleNode = ((Element) userNode).getElementsByTagName("role_id").item(0);
            Node servletNode = ((Element) userNode).getElementsByTagName("servlet").item(0);
            if (servletNode.getTextContent() != null) {
                String[] servletArray = servletNode.getTextContent().split(",");
                for (int j = 0; servletArray != null && j < servletArray.length; j++) {
                    authPage.add(roleNode.getTextContent(), servletArray[j]);
                }
            }
        }
        return authPage;
    }

    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="INNER CLASS - DataSource. Click on the + sign on the left to edit the code.">
    private class DatabaseSource implements IDataSource {

        String username;
        String password;
        String url;
        String driver;

        public DatabaseSource() {
            this.url = "";
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getUrl() {
            return this.url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getDriver() {
            return driver;
        }

        public void setDriver(String driver) {
            this.driver = driver;
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="INNER CLASS - SessionProcess. Click on the + sign on the left to edit the code.">
    protected class SessionProcess {

        HttpSession session;
        ArrayList<ISessionProperties> sessionProperties;

        SessionProcess(HttpSession session, ArrayList<ISessionProperties> sessionProperties) {
            if (session != null) {
                this.session = session;
                this.sessionProperties = sessionProperties;
            }
        }

        public Object getAttribute(String name) {
            if (this.getStatusByName(name).equals(ISessionProperties.ACTIVE_STATUS)) {
                return this.session.getAttribute(name);
            }
            return null;
        }

        public void setAttribute(String name, Object value) throws Exception {

            boolean hasSession = false;
            boolean isActiveStatus = true;

            for (int i = 0; !hasSession && i < this.sessionProperties.size(); i++) {
                if (this.sessionProperties.get(i).getName().equals(name)) {
                    hasSession = true;
                }
            }
            if (!hasSession) {
                throw new Exception(PropertiesBundle.EXCEPTION.getString("servlet.webpage.sessionprocess.text_1").replace("[#session_name#]", name));
            } else if (!this.getStatusByName(name).equals(ISessionProperties.ACTIVE_STATUS)) {
                isActiveStatus = false;
                throw new Exception(PropertiesBundle.EXCEPTION.getString("servlet.webpage.sessionprocess.text_3").replace("[#session_name#]", name));
            }

            if (isActiveStatus && hasSession) {
                this.session.setAttribute(name, value);
            }
        }

        public void removeAll() throws Exception {
            for (int i = 0; i < this.sessionProperties.size(); i++) {
                this.remove(this.sessionProperties.get(i).getName());
            }
        }

        public void remove(String name) {
            if (this.isAllowRemove(name)) {
                if (this.session.getAttribute(name) != null) {
                    this.session.removeAttribute(name);
                }
            }
        }

        public String getStatusByName(String name) {
            for (int i = 0; i < this.sessionProperties.size(); i++) {
                if (this.sessionProperties.get(i).getName().equals(name)) {
                    return this.sessionProperties.get(i).getStatus();
                }
            }
            return null;
        }

        public boolean isAllowRemove(String name) {
            for (int i = 0; i < this.sessionProperties.size(); i++) {
                if (this.sessionProperties.get(i).getName().equals(name)) {
                    return this.sessionProperties.get(i).isAllowRemove();
                }
            }
            return false;
        }
    }
    //</editor-fold>

    // <editor-fold defaultstate="collapsed" desc="INNER CLASS - SessionProperties. Click on the + sign on the left to edit the code.">
    protected class SessionProperties implements ISessionProperties {

        String name;
        String status;
        String isAllowRemove;

        public SessionProperties(String name, String status) {
            this.name = name;
            this.status = status;
            this.isAllowRemove = SessionProperties.ALLOW_REMOVE;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String getStatus() {
            return status;
        }

        @Override
        public boolean isAllowRemove() {
            if (this.isAllowRemove.equals(ISessionProperties.ALLOW_REMOVE)) {
                return true;
            } else if (this.isAllowRemove.equals(ISessionProperties.NOT_ALLOW_REMOVE)) {
                return false;
            }
            return true;
        }

        public void setAllowRemove(String stt) {
            this.isAllowRemove = stt;
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="CREAT COOKIE. Click on the + sign on the left to edit the code.">
    protected Cookie getCookie(String name, HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals(name)) {
                return cookies[i];
            }
        }
        return null;
    }

    protected Cookie getCookie(int maxAge, String value, String name, HttpServletRequest request) {
        Cookie cookie = this.getCookie(name, request);
        if (cookie != null) {
            cookie.setMaxAge(maxAge);
            cookie.setValue(value);
        }
        return cookie;
    }
    // </editor-fold>

    //FORWARD PAGE
    protected void forward(String path, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        request.getRequestDispatcher(path).forward(request, response);
    }

    //REDIRECT PAGE WITH SERVLET NAME
    protected void redirect(String servletName, HttpServletResponse response) throws IOException {
        response.sendRedirect(servletName);
    }
}
